package com.yfqy.app.util;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5加密工具类
 * 提供线程安全的MD5加密功能
 */
public final class MD5Util {

    private static final String MD5_ALGORITHM = "MD5";
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private static final String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    private MD5Util() {
        // 工具类，防止实例化
    }

    /**
     * MD5加密（使用UTF-8编码）
     *
     * @param source 原始字符串
     * @return MD5加密后的16进制字符串
     */
    public static String encrypt(String source) {
        return encrypt(source, DEFAULT_CHARSET);
    }

    /**
     * MD5加密（指定字符编码）
     *
     * @param source  原始字符串
     * @param charset 字符编码
     * @return MD5加密后的16进制字符串
     */
    public static String encrypt(String source, Charset charset) {
        if (source == null) {
            throw new IllegalArgumentException("Source string cannot be null");
        }

        try {
            MessageDigest md = MessageDigest.getInstance(MD5_ALGORITHM);
            byte[] digest = md.digest(source.getBytes(charset != null ? charset : DEFAULT_CHARSET));
            return bytesToHexString(digest);
        } catch (NoSuchAlgorithmException e) {
            // MD5算法在所有Java实现中都应该可用
            throw new IllegalStateException("MD5 algorithm not available", e);
        }
    }

    /**
     * 转换字节数组为16进制字符串（优化版本）
     */
    private static String bytesToHexString(byte[] bytes) {
        if (bytes == null) {
            return "";
        }

        StringBuilder hexString = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            hexString.append(HEX_DIGITS[(b >>> 4) & 0x0F]); // 取高4位
            hexString.append(HEX_DIGITS[b & 0x0F]);        // 取低4位
        }
        return hexString.toString();
    }

    /**
     * 验证字符串与MD5值是否匹配
     *
     * @param source   原始字符串
     * @param md5Value MD5值
     * @return 是否匹配
     */
    public static boolean verify(String source, String md5Value) {
        return verify(source, md5Value, DEFAULT_CHARSET);
    }

    /**
     * 验证字符串与MD5值是否匹配（指定编码）
     *
     * @param source   原始字符串
     * @param md5Value MD5值
     * @param charset  字符编码
     * @return 是否匹配
     */
    public static boolean verify(String source, String md5Value, Charset charset) {
        if (source == null || md5Value == null) {
            return false;
        }
        return encrypt(source, charset).equalsIgnoreCase(md5Value);
    }

}
